package com.ihome.android.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.ihome.android.EAApp;
import com.ihome.android.util.log.LogUtil;

/**
 * Remember add Permission "android.permission.DUMP" in Manifest.
 * <uses-permission android:name="android.permission.DUMP" />
 * 
 * @author Emerson
 */
public class AppUtils {
	public static final String	TAG				= AppUtils.class.getSimpleName();
	public static String		dumpPackageInfo	= "";

	/**
	 * get package info by package Name
	 * 
	 * @param ctx
	 *            Context
	 * @param pName
	 * @return PackageInfo if not find return null
	 */
	public static PackageInfo getPackageInfoByAppName(Context ctx, String pName) {
		PackageInfo pInfo = null;
		if (pName != null) {
			PackageManager pm = ctx.getPackageManager();
			try {
				pInfo = pm.getPackageInfo(pName, PackageManager.GET_SIGNATURES);
			} catch (NameNotFoundException e) {
				e.printStackTrace();
			}
		}
		return pInfo;
	}

	/**
	 * get app signature by package Name
	 * 
	 * @param ctx
	 * @param pName
	 * @return
	 */
	public static String getSignInfo(Context ctx, String pName) {

		String signinfo = "";
		try {
			PackageInfo packageInfo = getPackageInfoByAppName(ctx, pName);
			Signature[] signs = packageInfo.signatures;
			Signature sign = signs[0];
			// parseSignature(sign.toByteArray());
			signinfo = sign.toCharsString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return signinfo;
	}

	public static void parseSignature(byte[] signature) {
		try {
			CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
			X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signature));
			String pubKey = cert.getPublicKey().toString();
			String signNumber = cert.getSerialNumber().toString();
			System.out.println("signName:" + cert.getSigAlgName());
			System.out.println("pubKey:" + pubKey);
			System.out.println("signNumber:" + signNumber);
			System.out.println("subjectDN:" + cert.getSubjectDN().toString());
		} catch (CertificateException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * get App VersionName by package Name
	 * 
	 * @param ctx
	 * @param pName
	 * @return
	 */
	public static String getVersion(Context ctx, String pName) {
		String version = "";
		try {
			PackageInfo packageInfo = getPackageInfoByAppName(ctx, pName);
			version = packageInfo.versionName;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return version;
	}

	/**
	 * get App Name by package Name
	 * 
	 * @param ctx
	 * @param pName
	 * @return
	 */
	public static String getAppName(Context ctx, String pName) {
		CharSequence appName = "";

		PackageManager manager = ctx.getPackageManager();
		Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
		final int count = apps.size();
		for (int i = 0; i < count; i++) {
			ResolveInfo info = apps.get(i);
			if (info.activityInfo.applicationInfo.packageName.equals(pName)) {
				appName = info.loadLabel(manager);
			}
		}

		return appName.toString();
	}

	/**
	 * Get first start Activity Name and path by Package Name
	 * 
	 * @param pName
	 * @return
	 */
	public static String getStartActivityName(String pName) {
		if (TextUtils.isEmpty(dumpPackageInfo))
			dumpPackageInfo = excuteShellComm("dumpsys package " + pName);

		String filter = "android.intent.action.MAIN";
		try {
			String[] lines = dumpPackageInfo.split("\\n");
			for (int i = 0, len = lines.length; i < len; i++) {
				if (lines[i].contains(filter)) {
					String startActivityLine = lines[i + 1];

					String strArray[] = startActivityLine.split(" ");
					for (String str : strArray) {
						if (str.contains("/")) {
							return str;
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	public static boolean isSystemApp(String pName) {
		String filter = "codePath=/system/app";
		if (TextUtils.isEmpty(dumpPackageInfo))
			dumpPackageInfo = excuteShellComm("dumpsys package " + pName);

		if (!TextUtils.isEmpty(dumpPackageInfo)) {
			return dumpPackageInfo.contains(filter);
		}
		return false;
	}

	private void isSystemApp() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					//EALog.d(Market2App.class.getSimpleName(), "APK INSTALL PATH : " + Util.getApkPath(Market2App.this.getPackageName()));

					String[] findDataComm = new String[] { "find", "/system/app", "-name", "Com_IHOME_Market.apk" };

					EAApp.isSystemApp = Util.checkFileIsExistOrNot(findDataComm);

					LogUtil.d(EAApp.class.getSimpleName(), "is SystemApp : " + EAApp.isSystemApp);
				} catch (Exception e) {
					e.printStackTrace();
					LogUtil.e(EAApp.class.getSimpleName(), "is SystemApp Error : " + e.toString());
				}

			}
		}).start();
	}

	/**
	 * Get Apk File MD5 by Package Name
	 * 
	 * @param pName
	 * @return
	 */
	public static String getFileMD5(String pName) {
		String md5 = "";
		String codePath = "";
		if (TextUtils.isEmpty(dumpPackageInfo))
			dumpPackageInfo = excuteShellComm("dumpsys package " + pName);
		try {
			String[] lines = dumpPackageInfo.split("\\n");
			for (String str : lines) {
				if (str.contains("codePath")) {
					codePath = str.split("=")[1];
					break;
				}
			}
			String result = excuteShellComm("md5sum " + codePath.trim());
			if (!TextUtils.isEmpty(result) && result.contains(" ")) {
				md5 = result.split(" ")[0];
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return md5;
	}

	/**
	 * execute shell command and return output result
	 * 
	 * @param params
	 *            apk file path
	 * @return
	 */
	public static String excuteShellComm(String params) {
		String result = "";

		if (params == null)
			return "";

		String rsltStr = "";
		String errorStr = "";
		Process process = null;
		InputStream errIs = null;
		InputStream inIs = null;

		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			int read = -1;
			process = Runtime.getRuntime().exec(params);
			inIs = process.getInputStream();
			while ((read = inIs.read()) != -1) {
				baos.write(read);
			}
			baos.flush();
			byte[] data = baos.toByteArray();
			rsltStr = new String(data);

			Log.v(TAG, "excuteShellComm Result = " + rsltStr);
			if (!TextUtils.isEmpty(rsltStr)) {
				result = rsltStr;
			}
			else {
				baos.reset();
				errIs = process.getErrorStream();
				while ((read = errIs.read()) != -1) {
					baos.write(read);
				}
				baos.flush();
				byte[] data1 = baos.toByteArray();
				errorStr = new String(data1);
				result = errorStr;
				Log.e(TAG, "excuteShellComm --> Fail:" + params + "\n MSG:" + errorStr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (errIs != null) {
					errIs.close();
				}
				if (inIs != null) {
					inIs.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (process != null) {
				process.destroy();
			}
		}
		return result;
	}

	public static boolean checkAppInstallByPkgName(Context context, String pkgName) {
		boolean isInstalled = false;

		PackageManager pm = context.getPackageManager();
//		List<PackageInfo> lstPkg = pm.getInstalledPackages(0);
//		for (int i = 0; i < lstPkg.size(); i++) {
//			if (pkgName.equals(lstPkg.get(i).applicationInfo.packageName)) {
//				isInstalled = true;
//				break;
//			}
//		}
		Intent intent = pm.getLaunchIntentForPackage(pkgName);
		if (intent != null) {
			isInstalled = true;
		}
		LogUtil.v(TAG, "checkAppInstallByPkgName "+ pkgName + " isInstalled = " + isInstalled);
		return isInstalled;
	}

	public static void enableApp(Context ctx, String pName, boolean enable) {
		try {
			PackageManager pm = ctx.getPackageManager();
			if (enable)
				pm.setApplicationEnabledSetting(pName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
			else
				pm.setApplicationEnabledSetting(pName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String getProcessNameByPID(Context context, int pid) {
		String appName = null;
		ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

		for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
			if (processInfo.pid == pid) {
				appName = processInfo.processName;
				break;
			}
		}
		return appName;
	}

	/**
	 * 获取未安装的APK信息
	 * 
	 * @param context
	 * @param archiveFilePath
	 *            APK文件的路径。如：/sdcard/download/XX.apk
	 */
	public static PackageInfo getApkInfo(Context context, String archiveFilePath) {
		PackageManager pm = context.getPackageManager();
		PackageInfo apkInfo = pm.getPackageArchiveInfo(archiveFilePath, PackageManager.GET_META_DATA);
		return apkInfo;
	}

	/**
	 * 安装assets文件夹下的apk
	 * 
	 * @param context
	 *            上下文环境
	 * @param fileName
	 *            apk名称
	 * @param foldpath
	 *            安装文件路径
	 * @return
	 */
	public static List<String> getApkFromAssets(Context context, Object[] fileNames, String foldpath) {

		List<String> apkfiles = new ArrayList<String>();
		for (Object name : fileNames) {

			LogUtil.v(TAG, "getApkFromAssets " + "  name  = " + (String) name);
			try {
				InputStream is = context.getAssets().open((String) name);
				File fold = new File(foldpath);
				if (!fold.exists()) {
					fold.mkdirs();
				}
				File file = new File(foldpath, (String) name);
				file.createNewFile();
				FileOutputStream fos = new FileOutputStream(file);

				byte[] temp = new byte[1024];
				int i = 0;
				while ((i = is.read(temp)) > 0) {
					fos.write(temp, 0, i);
				}

				apkfiles.add(file.getAbsolutePath());
				Object[] chmodRusult = BgInstallApk.excuteShellComm("chmod 777 " + file.getAbsolutePath());
				LogUtil.v(TAG, "chmodRusult = " + ((Boolean)chmodRusult[0]).booleanValue());

				fos.close();
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return apkfiles;
	}

	public static boolean isPkgExist(Context context, String pkgName) {
		try {
			PackageManager packageManager = context.getPackageManager();
			Intent intent = packageManager.getLaunchIntentForPackage(pkgName);

			if (intent == null) {
				return false;
			}
			else {
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	/**
	 * Get App Package Name by app uid
	 * 
	 * @param context
	 * @param uid
	 * @return
	 */
	public static String getPkgNameByUid(Context context, int uid) {
		String pkgName = "";
		PackageManager pm = context.getPackageManager();
		List<PackageInfo> packinfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);
		for (PackageInfo info : packinfos) {
			int uid2 = info.applicationInfo.uid;
			if (uid == uid2) {
				pkgName = info.packageName;
				LogUtil.v(TAG, "getPkgNameByUid() --> pkgName = " + pkgName );
				break;
			}
		}
		return pkgName;
	}

	/**
	 * 打开APP的公共方法
	 * 
	 * @param context
	 * @param packageName
	 * @return
	 */
	public static boolean openApp(Context context, String packageName) {
		try {
			//			PackageManager packageManager = context.getPackageManager();
			//			PackageInfo pi = packageManager.getPackageInfo(packageName, 0);
			//
			//			Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
			//			resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
			//			resolveIntent.setPackage(pi.packageName);
			//
			//			List<ResolveInfo> apps = packageManager.queryIntentActivities(resolveIntent, 0);
			//
			//			if (apps != null) {
			//				final int count = apps.size();
			//				for (int i = 0; i < count; i++) {
			//					ResolveInfo info = apps.get(i);
			//					if (info.activityInfo.applicationInfo.packageName.equals(packageName)) {
			//						EALog.v(TAG, "App Name : " + info.loadLabel(packageManager) + "; pkgName = "
			//								+ info.activityInfo.applicationInfo.packageName);
			//
			//						String pkgname = info.activityInfo.applicationInfo.packageName;
			//						String className = info.activityInfo.name;
			//						ComponentName cn = new ComponentName(pkgname, className);
			//						Intent intent = new Intent(Intent.ACTION_MAIN);
			//						intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
			//						intent.addCategory(Intent.CATEGORY_LAUNCHER);
			//						intent.setComponent(cn);
			//						context.startActivity(intent);
			//						break;
			//					}
			//
			//				}
			//			}

			PackageManager packageManager = context.getPackageManager();
			Intent intent = packageManager.getLaunchIntentForPackage(packageName);
			context.startActivity(intent);
			return true;

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	public static void simulateKeystroke(final int KeyCode) {

		new Thread(new Runnable() {
			public void run() {
				try {
					Instrumentation inst = new Instrumentation();
					inst.sendKeyDownUpSync(KeyCode);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}).start();
	}

	public static void handleAppClick(Context mContext, String packageName) {

		if (openApp(mContext, packageName) == false) {
			Toast.makeText(mContext, "应用未安装", Toast.LENGTH_SHORT).show();
		}
	}

	public static void doInstallation(Context context, String apkpath) {
		try {
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			intent.setComponent(new ComponentName("com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity"));
			intent.setDataAndType(Uri.fromFile(new File(apkpath)), "application/vnd.android.package-archive");
			context.startActivity(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void doUnInstall(Context context, String apkPkgName) {
		try {
			Intent intent = new Intent();
			intent.setAction(Intent.ACTION_DELETE);
			intent.addCategory(Intent.CATEGORY_DEFAULT);
			intent.setData(Uri.parse("package:" + apkPkgName));
			context.startActivity(intent);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void getPermisson(Context context, String pkgName) {
		try {
			PackageManager pm = context.getPackageManager();
			//通过包名，返回包信息  PackageManager.PERMISSION_GRANTED
			PackageInfo pkgInfo = pm.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS);
			//得到权限列表  
			String sharedPkgList[] = pkgInfo.requestedPermissions;

			for (int i = 0; i < sharedPkgList.length; i++) {
				String permName = sharedPkgList[i];
				//通过permName得到该权限的详细信息  
				PermissionInfo tmpPermInfo = pm.getPermissionInfo(permName, 0);
				//权限分为不同的群组，通过权限名，我们得到该权限属于什么类型的权限。  
				PermissionGroupInfo pgi = pm.getPermissionGroupInfo(tmpPermInfo.group, 0);

				LogUtil.v(TAG, "getPermisson() --> permName = " + permName);
				LogUtil.v(TAG, "getPermisson() --> pgi.loadLabel(pm).toString() = " + pgi.loadLabel(pm).toString());
				LogUtil.v(TAG, "getPermisson() --> tmpPermInfo.loadLabel(pm).toString() = " + tmpPermInfo.loadLabel(pm).toString());
				LogUtil.v(TAG, "getPermisson() --> tmpPermInfo.loadDescription(pm).toString() = " + tmpPermInfo.loadDescription(pm).toString());

			}
		} catch (NameNotFoundException e) {
			e.printStackTrace();
			Log.e("##ddd", "Could not retrieve permissions for package");

		}
	}

}
